﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Xml;
using Open_MUD.Kernel.Utils;
using Open_MUD.Kernel.Interface.Client;

namespace Open_MUD.Kernel.Server.Services
{
    class AuthenticationService
    {
        private object varLock=new object();
        private static AuthenticationService __instance;
        const string USERBASE = "\\Data\\users\\";
        const string PJBASE = "\\Data\\players\\";
        const string USERFILEEXTENSION = ".xml";
        const string PJFILEEXTENSION = ".xml";

        public const int PJMINCHAR = 3;

        private String      cacheduser="";
        private XmlDocument cachedhandler=null;
        private DateTime    cachedtimestamp=DateTime.Now;
        

        public static AuthenticationService getInstance()
        {
            if (__instance == null)
                __instance = new AuthenticationService();

            return __instance;
        }

        public bool login(String user, String pass)
        { // TODO
            lock (varLock)
            {
                XmlDocument handler = new XmlDocument();
                handler.Load(userFile(user));
                String storedpass = handler.SelectSingleNode("user/password").InnerText;
                cacheduser = user;
                cachedhandler = handler;
                cachedtimestamp = DateTime.Now;
                return Util.getInstance().GetMD5Hash(pass).Equals(storedpass);                
            }
        }

        private string userFile(string user)
        {
            return Directory.GetCurrentDirectory() + USERBASE + user + USERFILEEXTENSION;
        }

        private string pjFile(string pjname)
        {
            return Directory.GetCurrentDirectory() + PJBASE + getPjBaseDir(pjname) + pjname + PJFILEEXTENSION;
        }

        public XmlDocument getPjXml(String pj)
        {
            XmlDocument handler = new XmlDocument();
            handler.Load(pjFile(pj));
            return handler;
        }

        private XmlDocument getClientXML(String user)
        {
            XmlDocument handler;
            if (cacheduser.Equals(user) && (cachedtimestamp.AddSeconds(1) > DateTime.Now))
                handler = cachedhandler;
            else
            {
                handler = new XmlDocument();
                handler.Load(userFile(user));
            }
            return handler;
        }

        internal String[] damePjs(String user)
        { // TODO
            lock (varLock)
            {
                XmlDocument handler = getClientXML(user);
                XmlNodeList players = handler.SelectNodes("user/players/player");
                String [] ret = new String[players.Count];
                int i = 0;
                foreach (XmlNode nodo in players)
                {
                    ret[i++] = nodo.InnerText;
                }
                return ret;
            }
        }

        internal void buildPath(string path)
        {
            string [] arrpath = path.Split('\\');
            string dirpath = Directory.GetCurrentDirectory();
            for ( int i=0; i < arrpath.Length ; i++ )
            {
                dirpath += "\\" + arrpath[i];
                if ( ! Directory.Exists( dirpath ) )
                    Directory.CreateDirectory(dirpath);
            }

        }

        internal string createPj(string pjname, string user)
        {
            lock(varLock)
            {
                pjname = pjname.Trim();
                pjname = pjname.ToLower();
                if (pjname.Contains(' '))
                    throw new MudException("Nombre no válido");
                buildPath(PJBASE + getPjBaseDir(pjname));
                string path = pjFile(pjname);
                FileStream fs = File.Create(path);
                fs.Close();
                string pjdata = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>"+
                "<player>"+
                  "<long></long>"+
                  "<level>2</level>"+
                  "<race>stark</race>"+
                  "<subrace>stark</subrace>"+
                  "<clase>Guardia de la Noche</clase>"+
                  "<edad>20</edad>"+
                  "<ciudadania>Invernalia</ciudadania>"+
                  "<localizacion tipo=\"mapa_exterior\">1234,335</localizacion>"+
                  "<altura>1,80</altura>"+
                  "<ojos>verdes</ojos>"+
                  "<pelo>castaño</pelo>"+
                  "<complexion>fuerte</complexion>"+
                  "<fuerza>18</fuerza>"+
                  "<destreza>18</destreza>"+
                  "<inteligencia>18</inteligencia>"+
                  "<carisma>18</carisma>"+
                  "<sabiduria>18</sabiduria>"+
                  "<constitucion>18</constitucion>"+
                  "<reflejos>18</reflejos>"+
                  "<voluntad>18</voluntad>"+
                  "<fortaleza>18</fortaleza>"+
                  "<PF>30</PF>"+
                "</player>";
                File.WriteAllText(path, pjdata);

                XmlDocument handler = getClientXML(user);
                XmlNode elem = handler.CreateNode(XmlNodeType.Element, "player", "");                
                elem.InnerText = pjname;
                XmlNodeList pjs = handler.GetElementsByTagName("players");
                if (pjs.Count != 1 )
                {
                    throw new MudException("Error grave en la configuracion de tu cuenta");
                }
                pjs[0].AppendChild(elem);
                handler.Save(userFile(user));
            }
            return pjname;
        }

        internal bool existUser(string user)
        {
            return File.Exists(userFile(user));
        }

        internal void newUser(string user, string pass)
        {
            TextWriter tw = new StreamWriter(Directory.GetCurrentDirectory() + USERBASE + user + USERFILEEXTENSION);
            tw.WriteLine("<?xml version=\"1.0\" encoding=\"utf-8\" ?>");
            tw.WriteLine("<user>");
            tw.WriteLine("<password>"+Util.getInstance().GetMD5Hash(pass)+"</password>");
            tw.WriteLine("<players>");
            tw.WriteLine("</players>");
            tw.WriteLine("</user>");
            tw.Close();
        }

        private String getPjBaseDir(String playername)
        {
            return playername[0] + "\\" + playername[1] + "\\" + playername[2] + "\\";
        }

        internal bool existePj(string playername)
        {
            return File.Exists(Directory.GetCurrentDirectory() + PJBASE + getPjBaseDir(playername) + playername + PJFILEEXTENSION );
        }

        internal string checkPjName(string playername)
        {
            if (existePj(playername))
                return "Ese personaje ya existe.%^ret%^Introduce un nuevo nombre para tu personaje";
            if (playername.Length < PJMINCHAR)
                return "El nombre del personaje es demasiado corto. La longitud minima es " + PJMINCHAR;
            if (estaBaneado(playername))
                return "El personaje se encuentra baneado. Consulte un Guardian para más información.";

            //no problems
            return "";
        }

        private bool estaBaneado(string personaje)
        {
            return false;
        }
    }
}
